# 作用域（scope）
# 作用域是指变量生效的区域

b = 20  # 全局变量


def fn():
    a = 10  # 函数内部定义的变量，函数外部无法访问
    print('函数内部：', a)
    print('函数内部：', b)


fn()
print('====================分割线======================')


# print('函数内部：', a)
# print('函数外部：', b)

# python有两种作用域
# 全局作用域
#   - 全局作用域是在程序执行时创建的，在程序执行结束时销毁
#   - 所有函数以外的区域都属于全局作用域
#   - 在全局作用域定义的变量，都属于全局变量，可以在程序的任意位置被访问
# 函数作用域
#   - 函数作用域是在函数调用时创建，在调用结束时销毁
#   - 函数每调用一次就会产生一个新的函数作用域
#   - 在函数中定义的变量，都属于局部变量，只能在函数内部被访问
# 变量的查找
#   - 当我们使用一个变量时，会优先在当前作用域中寻找该变量，如果有则使用，如果没有，则继续
# 去上一级作用域中寻找，如果上级也没有，则继续向上上一级寻找，以此类推，直到找到全局作用域
# 依然没有找到，就会抛出异常：NameError：name 'a' is not defined


def fn2():
    a = 30

    def fn3():
        print('fn3中:', 'a =', a)

    fn3()


fn2()

print('====================分割线======================')

a = 50


def fn3():
    # a = 10 # 在函数中为变量赋值，默认都是局部变量
    # 如果希望在函数内部修改全局变量，则需要使用关键字global，来声明变量
    global a  # 声明在函数内部使用的变量a是全局变量，此时再去修改a，就是在修改全局变量
    a = 40
    print('函数内部:', 'a =', a)


fn3()
print('函数外部:', 'a =', a)

# 命名空间（namespace）
# 命名空间是指变量存储的位置，每个变量都需要存储到指定的命名空间当中
# 每个作用域都有它对应的命名空间
# 全局命名空间，用来保存全局变量，函数命名空间用来保存函数中的变量
# 命名空间实际上就是一个字典，是一个专门用来存储变量的字典

# locals()用来获取当前作用域的命名空间
# 如果在全局作用域中调用locals（），则获取全局命名空间，如果在函数作用域中
# 调用locals则获取函数的命名空间
scope = locals()  # 当前命名空间
print(scope)
print(type(scope))
# print(scope['a'])

# 向scope中添加一对key-value

scope['c'] = 1000  # 向字典中添加key-value就相当于在全局中创建了一个变量（不建议）


# print(c)


def fn4():
    # a = 10
    # scope = locals()  # 在函数内部调用locals()会获取函数的命名空间
    # scope['b'] = 20  # 可以通过scope来操作函数的命名空间，但不建议这么做
    # globals()函数可以在函数内获取全局命名空间
    global_scope = globals()
    print(global_scope['a'])
    global_scope['a'] = 30
    print(global_scope['a'])
    # print(b)
    # print(scope)


fn4()
